package com.swak.devtools.apidoc.parse.parser;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletionStage;

import org.springframework.beans.BeanUtils;

import com.swak.asm.ParameterizedTypeImpl;
import com.swak.devtools.apidoc.parse.ApiClass;
import com.swak.entity.UploadFile;
import com.swak.exception.BaseRuntimeException;
import com.swak.reactivex.context.ReferenceThreadContext;
import com.swak.security.Platform;
import com.swak.security.Subject;
import com.swak.utils.Maps;
import com.swak.utils.StringUtils;
import com.swak.validator.errors.BindErrors;
import com.swak.vertx.protocol.im.ImContext;
import com.swak.vertx.protocol.im.ImContext.ImRequest;
import com.swak.vertx.protocol.im.ImContext.ImResponse;
import com.swak.vertx.remote.IP;

import io.vertx.core.http.HttpServerRequest;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.ext.web.RoutingContext;
import lombok.Data;
import lombok.experimental.Accessors;

/**
 * 通用的处理类;
 * 
 * @author 618lf
 */
public class AbstractParser {

	public static final String PARAM_CLASS_SPLIT = ",";
	public static final String EMPTY_PARAM = "void";

	/**
	 * 解析的参数
	 * 
	 * @author 618lf
	 */
	@Data
	@Accessors(chain = true)
	protected static class ActualClass {
		private Type type;
		private Class<?> clazz;
		private Map<TypeVariable<?>, Type> parameters;
	}

	/**
	 * 解析的结果
	 * 
	 * @author 618lf
	 */
	@Data
	@Accessors(chain = true)
	protected static class ParsedClass {
		private ActualClass param;
		private ApiClass apiClass;
	}

	/**
	 * 解析统计：存储在线程中,解决循环解析的问题;  
	 * 遇到循环解析的类，则不再继续解析;  
	 *  
	 * @author 618lf
	 */
	@Data
	@Accessors(chain = true)
	protected static class ParsedStat {
		final static ReferenceThreadContext<ParsedStat> CONTEXT = new ReferenceThreadContext<>();
		private Map<Class<?>, Integer> deeps = Maps.newHashMap();

		public static void start() {
			ParsedStat stat = new ParsedStat();
			CONTEXT.bind(stat);
		}

		public static void parsed(Class<?> clazz) {
			ParsedStat stat = CONTEXT.get();
			if (stat != null) {
				Integer deep = stat.deeps.get(clazz);
				deep = deep == null ? 1 : deep + 1;
				stat.deeps.put(clazz, deep);
			}
		}

		public static boolean isCycleParse(Class<?> clazz, int max) {
			ParsedStat stat = CONTEXT.get();
			return stat != null && stat.deeps.get(clazz) != null && stat.deeps.get(clazz) >= max;
		}

		public static void finish() {
			CONTEXT.remove();
		}
	}

	// 解析 class
	protected static ParsedClass parseClass(Type type, // 类型
			Class<?> clazz, // class 类型
			Map<TypeVariable<?>, Type> parameters) {// 参数

		// 解析出实际的类型
		ActualClass actualClass = parseActualClass(type, clazz, parameters);

		// 解决循环依赖的问题
		Class<?> realClazz = actualClass.getClazz();
		boolean checkAble = realClazz != null && realClazz instanceof Class;
		if (checkAble && ParsedStat.isCycleParse(realClazz, 1)) {
			return new ParsedClass().setParam(actualClass);
		}

		// 记录已解析
		if (checkAble && needParse(actualClass.getClazz())) {
			ParsedStat.parsed(realClazz);
		}

		// 处理具体的类型 -- 不需要处理基本类型
		ApiClass apiClass = null;
		if (needParse(actualClass.getClazz())) {
			apiClass = ClassParser.of(actualClass) // 创建类解析器
					.setParseMethod(false) // 不需要解析方法
					.parse();// 执行解析
		}

		// 返回处理的Class
		return new ParsedClass().setParam(actualClass).setApiClass(apiClass);
	}

	// 处理请求地址
	protected static Set<String> prependLeadingSlash(Collection<String> patterns) {
		if (patterns == null) {
			return Collections.emptySet();
		}
		Set<String> result = new LinkedHashSet<String>(patterns.size());
		for (String pattern : patterns) {
			if (StringUtils.hasLength(pattern) && !pattern.startsWith("/")) {
				pattern = new StringBuilder("/").append(pattern).toString();
			}
			result.add(pattern);
		}
		return result;
	}

	protected static String buildClassName(Class<?> c) {
		if (c.isArray()) {
			StringBuilder sb = new StringBuilder();
			do {
				sb.append("[]");
				c = c.getComponentType();
			} while (c.isArray());

			return c.getName() + sb.toString();
		}
		return c.getName();
	}

	protected static Class<?>[] parseMethodParams(Method method, Map<TypeVariable<?>, Type> parameters) {
		Class<?>[] actualTypes = method.getParameterTypes();
		Type[] parameterTypes = method.getGenericParameterTypes();
		if (parameters != null && actualTypes.length > 0 && parameterTypes != null && parameterTypes.length > 0) {
			for (int i = 0; i < parameterTypes.length; i++) {
				if (parameterTypes[i] instanceof TypeVariable) {
					ActualClass actualClass = parseActualClass(parameterTypes[i], actualTypes[i], parameters);
					actualTypes[i] = actualClass.getClazz();
				}
			}
		}
		return actualTypes;
	}

	/**
	 * 解析出实际的类型
	 * 
	 * @param param
	 * @return
	 */
	protected static ActualClass parseActualClass(Type type, // 类型
			Class<?> clazz, // class 类型
			Map<TypeVariable<?>, Type> parameters) {// 参数

		// 解析出的参数
		Type actualType = type;// type
		Class<?> actualClass = clazz; // class 类型
		Map<TypeVariable<?>, Type> actualMappers = parameters; // 参数

		// 尝试解析
		if (type instanceof Class) {
			actualClass = (Class<?>) type;
		} else if (type instanceof ParameterizedType) {
			ParameterizedType parameterizedType = (ParameterizedType) type;
			actualMappers = paramVariablesMappers(parameterizedType.getActualTypeArguments(),
					((Class<?>) parameterizedType.getRawType()).getTypeParameters(), parameters);
			actualClass = (Class<?>) parameterizedType.getRawType();
			if (List.class.isAssignableFrom(actualClass) || Set.class.isAssignableFrom(actualClass)) {
				return new ActualClass().setType(actualType).setClazz(actualClass).setParameters(parameters);
			} else if (CompletionStage.class.isAssignableFrom(actualClass)) {
				actualType = parameterizedType.getActualTypeArguments()[0];
				return parseActualClass(actualType, actualClass, parameters);
			}
		} else if (parameters != null && type instanceof TypeVariable) {
			actualType = parameters.get(type);
			return parseActualClass(actualType, actualClass, parameters);
		}

		// 返回解析出的数据
		return new ActualClass().setType(actualType).setClazz(actualClass).setParameters(actualMappers);
	}

	protected static boolean isArray(Class<?> type) {
		return type.isArray();
	}

	protected static boolean isCollection(Class<?> type) {
		return List.class.isAssignableFrom(type) || Set.class.isAssignableFrom(type);
	}

	protected static boolean needParse(Class<?> parameterType) {
		if (parameterType == null //
				|| HttpServerRequest.class.isAssignableFrom(parameterType)//
				|| HttpServerResponse.class.isAssignableFrom(parameterType)//
				|| RoutingContext.class.isAssignableFrom(parameterType) //
				|| IP.class.isAssignableFrom(parameterType)//
				|| ImRequest.class.isAssignableFrom(parameterType) //
				|| ImResponse.class.isAssignableFrom(parameterType)//
				|| ImContext.class.isAssignableFrom(parameterType) //
				|| Subject.class.isAssignableFrom(parameterType)//
				|| BindErrors.class.isAssignableFrom(parameterType) //
				|| BeanUtils.isSimpleProperty(parameterType)//
				// || Collection.class.isAssignableFrom(parameterType) //
				// || List.class.isAssignableFrom(parameterType)//
				// || Map.class.isAssignableFrom(parameterType) //
				|| UploadFile.class.isAssignableFrom(parameterType)//
				|| Platform.class.isAssignableFrom(parameterType)) {//
			return false;
		}
		return true;
	}

	protected static Map<TypeVariable<?>, Type> paramVariablesMappers(Type[] actualTypes,
			TypeVariable<?>[] typeParameters, Map<TypeVariable<?>, Type> actualMappers) {

		// 类型变量和实际类型映射
		Map<TypeVariable<?>, Type> paramVariablesMappers = Maps.newHashMap();
		for (int i = 0; i < typeParameters.length; i++) {

			// 实际的类型
			Type actualType = actualTypes[i];

			// 如果实际类型直接是类类型
			if (actualType instanceof Class) {
				actualType = actualTypes[i];
			}
			// 如果实际类型是 参数类型
			else if (actualType instanceof ParameterizedType || actualType instanceof TypeVariable) {
				actualType = getActualParameterizedType(actualType, actualMappers);
			}
			// 不支持的格式
			else {
				throw new BaseRuntimeException("Type Parameter Not Support " + actualType);
			}
			paramVariablesMappers.put(typeParameters[i], actualType);
		}
		return paramVariablesMappers;
	}

	protected static Type getActualParameterizedType(Type type, Map<TypeVariable<?>, Type> actualMappers) {
		if (actualMappers == null) {
			return type;
		}
		if (type instanceof ParameterizedType) {
			ParameterizedType parameterizedType = (ParameterizedType) type;
			Type[] aTypes = parameterizedType.getActualTypeArguments();
			Type[] nestTypes = new Type[aTypes.length];
			for (int i = 0; i < aTypes.length; i++) {
				Type aType = aTypes[i];
				if (aType instanceof Class) {
					nestTypes[i] = aType;
				} else if (aType instanceof TypeVariable) {
					nestTypes[i] = actualMappers.get(aType);
				} else {
					throw new BaseRuntimeException("Actual Type Arguments Not Support " + aType);
				}
			}
			return new ParameterizedTypeImpl(nestTypes, parameterizedType.getOwnerType(),
					parameterizedType.getRawType());
		} else if (type instanceof TypeVariable) {
			return actualMappers.get(type);
		}
		throw new BaseRuntimeException("not support");
	}
}
